#include <sys/time.h>
#include <sys/prctl.h>
#include <sys/syscall.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <stddef.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/mman.h>
#include <sys/shm.h>
#include <poll.h>
#include <sys/epoll.h>
#include <sys/select.h>
#include <dirent.h>
#include <malloc.h>
#include <sys/types.h>
#include <sys/wait.h>
#include "tuya_cloud_base_defs.h"
#include "tuya_ipc_dp_utils.h"
#include "tuya_ipc_cloud_storage.h"
#include "tuya_ipc_common_demo.h"
#include "tuya_ipc_system_control_demo.h"
#include "tuya_ipc_media_demo.h"
#include "tuya_ipc_motion_detect_demo.h"
#include "tuya_iot_config.h"
#include "tuya_ipc_sdk_simple_start.h"
#include "tuya_ipc_p2p_demo.h"
#include "tuya_ipc_upgrade_demo.h"
#include "tuya_ipc_sd_demo.h"
#include "tuya_ipc_upgrade_demo.h"
#include "tuya_ipc_video_proc.h"
#include "tuya_ipc_sdk_simple_start.h"
#include "tuya_os_adapt_bt.h"
#include "InCommon.h"
#include "SdkSwitchNetMode.h"
#include "SdkMediaInit.h"
#include "InPerLed.h"
#include "tuya_ipc_qrcode_demo.h"
#include "SdkWatchingHandle.h"
#include "InSdkSignalFunc.h"
#include "InSdkCallbackFunction.h"
#include "InPerKey.h"
#include "InSdkDevInfo.h"
#include "InSdkIniBasic.h"
#include "InSdkIniDev.h"
#include "InSdkSaveLastDate.h"
#include "InSdkSoundPlay.h"
#include "InSdkSpkCtrl.h"
#include "InSdkRebootEveryday.h"

#if CMAKE_SUPPORT_STEP_MOTOR
#include "InPerSteppingMotor.h"
#endif

#define DEF_TAG         "TYMain"

#define IPC_APP_STORAGE_PATH    "/mnt/config/"   //Path to save tuya sdk DB files, should be readable, writeable and storable
#define IPC_APP_UPGRADE_FILE    "/tmp/upgrade.tar" //File with path to download file during OTA
#define IPC_APP_SD_BASE_PATH    "/mnt/config/record/"      //SD card mount directory

/*cloud storage (custome whether enable or not)*/
/*if no ase,it can equal NULL;*/
extern OPERATE_RET AES_CBC_init(VOID);
extern OPERATE_RET AES_CBC_encrypt(IN BYTE_T *pdata_in,  IN UINT_T data_len,
                                   INOUT BYTE_T *pdata_out,  OUT UINT_T *pdata_out_len,
                                   IN BYTE_T *pkey, IN BYTE_T *piv);
extern OPERATE_RET AES_CBC_destory(VOID);

Com_u8 g_ComThread_Running;
Com_u32 g_ComThread_Num = 0;
char IPC_APP_UUID[DEF_COM_UUID_LEN];
char IPC_APP_AUTHKEY[DEF_COM_KEY_LEN];
char IPC_APP_PID[DEF_COM_PID_LEN];
char IPC_APP_VERSION[DEF_COM_VERSION_LEN];

STATIC INT_T s_mqtt_status = 0;
CHAR_T s_raw_path[128] = {0};

STATIC VOID __IPC_APP_Get_Net_Status_cb(IN CONST BYTE_T stat)
{
    PR_DEBUG("Net status change to:%d", stat);

    switch(stat)
    {
#if defined(WIFI_GW) && (WIFI_GW==1)
    case STAT_CLOUD_CONN:        //for wifi ipc
    case STAT_MQTT_ONLINE:       //for low-power wifi ipc
#endif
#if defined(WIFI_GW) && (WIFI_GW==0)
    case GB_STAT_CLOUD_CONN:     //for wired ipc
#endif
    {
        IPC_APP_Notify_LED_Sound_Status_CB(IPC_MQTT_ONLINE);
        PR_DEBUG("mqtt is online\r\n");
        s_mqtt_status = 1;
        break;
    }

    case STAT_STA_DISC:
    {
        PRT_DBG(DEF_TAG,"sta is connecting\n");
        break;
    }

    default:
    {
        break;
    }
    }
}

OPERATE_RET TUYA_IPC_SDK_START(WIFI_INIT_MODE_E connect_mode, CHAR_T *p_token)
{
    PRT_DBG(DEF_TAG,"SDK Version: %s\n", tuya_ipc_get_sdk_info());
    TUYA_IPC_SDK_RUN_VAR_S ipc_sdk_run_var = {{{0}}};
    memset(&ipc_sdk_run_var,0,sizeof(ipc_sdk_run_var));

    /*certification information(essential)*/
    strcpy(ipc_sdk_run_var.iot_info.product_key,IPC_APP_PID);
    strcpy(ipc_sdk_run_var.iot_info.uuid,IPC_APP_UUID);
    strcpy(ipc_sdk_run_var.iot_info.auth_key,IPC_APP_AUTHKEY);
    strcpy(ipc_sdk_run_var.iot_info.dev_sw_version,IPC_APP_VERSION);
    strcpy(ipc_sdk_run_var.iot_info.cfg_storage_path,IPC_APP_STORAGE_PATH);
    ipc_sdk_run_var.iot_info.dev_type = NORMAL_POWER_DEV;//LOW_POWER_DEV;

    /*connect mode (essential)*/
    ipc_sdk_run_var.net_info.connect_mode = connect_mode;
    ipc_sdk_run_var.net_info.net_status_change_cb = __IPC_APP_Get_Net_Status_cb;
    if(p_token)
    {
        strcpy(ipc_sdk_run_var.debug_info.qrcode_token,p_token);
    }

    /*media info (essential)*/
    /* main stream(HD), video configuration*/
    /* NOTE
    FIRST:If the main stream supports multiple video stream configurations, set each item to the upper limit of the allowed configuration.
    SECOND:E_IPC_STREAM_VIDEO_MAIN must exist.It is the data source of SDK.
    please close the E_IPC_STREAM_VIDEO_SUB for only one stream*/
    ipc_sdk_run_var.media_info.media_info.channel_enable[E_IPC_STREAM_VIDEO_MAIN] = TRUE;    /* Whether to enable local HD video streaming */
    ipc_sdk_run_var.media_info.media_info.video_fps[E_IPC_STREAM_VIDEO_MAIN] = DEF_SDK_VIDEO_FPS;  /* FPS */
    ipc_sdk_run_var.media_info.media_info.video_gop[E_IPC_STREAM_VIDEO_MAIN] = DEF_SDK_VIDEO_FPS * 3;  /* GOP */
    ipc_sdk_run_var.media_info.media_info.video_bitrate[E_IPC_STREAM_VIDEO_MAIN] = TUYA_VIDEO_BITRATE_1_5M; /* Rate limit */
    ipc_sdk_run_var.media_info.media_info.video_width[E_IPC_STREAM_VIDEO_MAIN] = SENSOR_MAIN_WIDTH; /* Single frame resolution of width*/
    ipc_sdk_run_var.media_info.media_info.video_height[E_IPC_STREAM_VIDEO_MAIN] = SENSOR_MAIN_HEIGHT;/* Single frame resolution of height */

    if(Ext_InComFile_Access(DEF_SENSOR_INFO_QXGA) == DEF_COM_FILE_EXIST)
    {
        ipc_sdk_run_var.media_info.media_info.video_bitrate[E_IPC_STREAM_VIDEO_MAIN] = TUYA_VIDEO_BITRATE_1_5M; /* Rate limit */
        ipc_sdk_run_var.media_info.media_info.video_width[E_IPC_STREAM_VIDEO_MAIN] = DEF_SENSOR_QXGA_WIDTH;
        ipc_sdk_run_var.media_info.media_info.video_height[E_IPC_STREAM_VIDEO_MAIN] = DEF_SENSOR_QXGA_HEIGHT;
    }
    else
    {
        ipc_sdk_run_var.media_info.media_info.video_width[E_IPC_STREAM_VIDEO_MAIN] = DEF_SENSOR_1080P_WIDTH;
        ipc_sdk_run_var.media_info.media_info.video_height[E_IPC_STREAM_VIDEO_MAIN] = DEF_SENSOR_1080P_HEIGHT;
    }

    ipc_sdk_run_var.media_info.media_info.video_freq[E_IPC_STREAM_VIDEO_MAIN] = 90000; /* Clock frequency */
    ipc_sdk_run_var.media_info.media_info.video_codec[E_IPC_STREAM_VIDEO_MAIN] = TUYA_CODEC_VIDEO_H265; /* Encoding format */
    /* substream(HD), video configuration */
    /* Please note that if the substream supports multiple video stream configurations, please set each item to the upper limit of the allowed configuration. */
    ipc_sdk_run_var.media_info.media_info.channel_enable[E_IPC_STREAM_VIDEO_SUB] = TRUE;     /* Whether to enable local SD video stream */
    ipc_sdk_run_var.media_info.media_info.video_fps[E_IPC_STREAM_VIDEO_SUB] = DEF_SDK_VIDEO_FPS;  /* FPS */
    ipc_sdk_run_var.media_info.media_info.video_gop[E_IPC_STREAM_VIDEO_SUB] = DEF_SDK_VIDEO_FPS * 3;  /* GOP */
    ipc_sdk_run_var.media_info.media_info.video_bitrate[E_IPC_STREAM_VIDEO_SUB] = TUYA_VIDEO_BITRATE_512K; /* Rate limit */
    ipc_sdk_run_var.media_info.media_info.video_width[E_IPC_STREAM_VIDEO_SUB] = SENSOR_SUB_WIDTH; /* Single frame resolution of width */
    ipc_sdk_run_var.media_info.media_info.video_height[E_IPC_STREAM_VIDEO_SUB] = SENSOR_SUB_HEIGHT;/* Single frame resolution of height */
    ipc_sdk_run_var.media_info.media_info.video_freq[E_IPC_STREAM_VIDEO_SUB] = 90000; /* Clock frequency */
    ipc_sdk_run_var.media_info.media_info.video_codec[E_IPC_STREAM_VIDEO_SUB] = TUYA_CODEC_VIDEO_H265; /* Encoding format */
    /* Audio stream configuration.
    Note: The internal P2P preview, cloud storage, and local storage of the SDK are all use E_IPC_STREAM_AUDIO_MAIN data. */
    ipc_sdk_run_var.media_info.media_info.channel_enable[E_IPC_STREAM_AUDIO_MAIN] = TRUE;         /* Whether to enable local sound collection */
    ipc_sdk_run_var.media_info.media_info.audio_codec[E_IPC_STREAM_AUDIO_MAIN] = TUYA_CODEC_AUDIO_G711A;/* Encoding format */
    ipc_sdk_run_var.media_info.media_info.audio_sample [E_IPC_STREAM_AUDIO_MAIN]= TUYA_AUDIO_SAMPLE_8K;/* Sampling Rate */
    ipc_sdk_run_var.media_info.media_info.audio_databits [E_IPC_STREAM_AUDIO_MAIN]= TUYA_AUDIO_DATABITS_16;/* Bit width */
    ipc_sdk_run_var.media_info.media_info.audio_channel[E_IPC_STREAM_AUDIO_MAIN]= TUYA_AUDIO_CHANNEL_MONO;/* channel */
    ipc_sdk_run_var.media_info.media_info.audio_fps[E_IPC_STREAM_AUDIO_MAIN] = 25;/* Fragments per second */

    /*local storage (custome whether enable or not)*/
#if CMAKE_SUPPORT_SD_RECORD
    ipc_sdk_run_var.local_storage_info.enable = 1;
#else
    ipc_sdk_run_var.local_storage_info.enable = 0;
#endif
    ipc_sdk_run_var.local_storage_info.max_event_num_per_day = 500;
    ipc_sdk_run_var.local_storage_info.skills = 0;//0 means all skills
    ipc_sdk_run_var.local_storage_info.sd_status_cb = tuya_ipc_sd_status_upload;
    strcpy(ipc_sdk_run_var.local_storage_info.storage_path, IPC_APP_SD_BASE_PATH);

    ipc_sdk_run_var.cloud_storage_info.enable = 1;
    ipc_sdk_run_var.aes_hw_info.aes_fun.init = AES_CBC_init;
    ipc_sdk_run_var.aes_hw_info.aes_fun.encrypt = AES_CBC_encrypt;
    ipc_sdk_run_var.aes_hw_info.aes_fun.destory = AES_CBC_destory;

    /*p2p function (essential)*/
    ipc_sdk_run_var.p2p_info.max_p2p_client = DEF_MAX_P2P_USER_NUM;
    ipc_sdk_run_var.p2p_info.live_mode = TRANS_DEFAULT_STANDARD;
    ipc_sdk_run_var.p2p_info.transfer_event_cb = __TUYA_APP_p2p_event_cb;
    ipc_sdk_run_var.p2p_info.rev_audio_cb = __TUYA_APP_rev_audio_cb;

    /*AI detect (custome whether enable or not)*/
    ipc_sdk_run_var.cloud_ai_detct_info.enable = 0;

    /*door bell (custome whether enable or not)*/
    ipc_sdk_run_var.video_msg_info.enable = 0;
    ipc_sdk_run_var.video_msg_info.type = MSG_BOTH;
    ipc_sdk_run_var.video_msg_info.msg_duration = 10;

    /*dp function(essential)*/
    ipc_sdk_run_var.dp_info.dp_query = IPC_APP_handle_dp_query_objs;
    ipc_sdk_run_var.dp_info.raw_dp_cmd_proc = IPC_APP_handle_raw_dp_cmd_objs;
    ipc_sdk_run_var.dp_info.common_dp_cmd_proc = IPC_APP_handle_dp_cmd_objs;

    /*upgrade function(essential)*/
    ipc_sdk_run_var.upgrade_info.enable = true;
    ipc_sdk_run_var.upgrade_info.upgrade_cb = IPC_APP_Upgrade_Inform_cb;

    ipc_sdk_run_var.iot_info.gw_reset_cb = IPC_APP_Reset_System_CB;
    ipc_sdk_run_var.iot_info.gw_restart_cb = IPC_APP_Restart_Process_CB;

    OPERATE_RET ret ;
    ret = tuya_ipc_sdk_start(&ipc_sdk_run_var);
    if(ret !=0 )
    {
        PRT_ERR(DEF_TAG,"ipc sdk v5 start fail,please check run parameter，ret=%d\n",ret);
    }
    return ret;
}

Com_s32 Sdk_GetDev_AllInfo(void)
{
    Com_s32 ret = DEF_COM_FAILED;

    memset(IPC_APP_PID,0,sizeof(IPC_APP_PID));
    memset(IPC_APP_UUID,0,sizeof(IPC_APP_UUID));
    memset(IPC_APP_AUTHKEY,0,sizeof(IPC_APP_AUTHKEY));
    memset(IPC_APP_VERSION,0,sizeof(IPC_APP_VERSION));

    /* get device UUID */
    ret = Ext_InSdkGetInfo_UUID(IPC_APP_UUID);
    if(ret != DEF_COM_SUCCESS)
    {
        PRT_ERR(DEF_TAG,"get uuid failed\n");
        return DEF_COM_FAILED;
    }

    /*get device AUTHKEY */
    ret = Ext_InSdkGetInfo_Authkey(IPC_APP_AUTHKEY);
    if(ret != DEF_COM_SUCCESS)
    {
        PRT_ERR(DEF_TAG,"get authkey failed\n");
        return DEF_COM_FAILED;
    }

    /*get device PID */
    ret = Ext_InSdkGetInfo_Pid(IPC_APP_PID);
    if(ret != DEF_COM_SUCCESS)
    {
        PRT_ERR(DEF_TAG,"get pid failed\n");
        return DEF_COM_FAILED;
    }

    /* get firmware version */
    ret = Ext_InSdkGetInfo_AllVer(IPC_APP_VERSION);
    if(ret != DEF_COM_SUCCESS)
    {
        PRT_ERR(DEF_TAG,"get firmware version failed\n");
        return DEF_COM_FAILED;
    }

    return DEF_COM_SUCCESS;
}

void tuya_ipc_doorbell_event(void)
{
}

VOID IPC_APP_Init_Media_Task(VOID)
{
    pthread_t mic_id;
    pthread_create(&mic_id, NULL, thread_live_audio, NULL);
    pthread_detach(mic_id);

#if CMAKE_SUPPORT_QRCODE
    Ext_SdkQRcode_Init();
#endif

    pthread_t m_video_id;
    pthread_create(&m_video_id, NULL, thread_live_mainvideo, NULL);
    pthread_detach(m_video_id);

    pthread_t s_video_id;
    pthread_create(&s_video_id, NULL, thread_live_subvideo, NULL);
    pthread_detach(s_video_id);

    return;
}

VOID TUYA_APP_Enable_Motion_Detect(VOID)
{
    pthread_t md_id;
    pthread_create(&md_id, NULL, thread_md_proc, NULL);
    pthread_detach(md_id);
}

int main(void)
{
    g_ComThread_Running = DEF_COM_TRUE;

    WIFI_INIT_MODE_E mode;
    Com_s32 ret = DEF_COM_FAILED;

    Ext_InSdkIniCfg_Init();
    Ext_SdkGpio_Init();
    /* get timezone */
    Ext_InComTimer_SetTZSec(Ext_InSdkIniBasic_GetVal(INI_BASIC_TIME_TZ_SEC));
    Ext_InSdkSaveDate_Init();
    //Ext_InPerUart_Init();
    Ext_InSdkSignal_Init();

#if CMAKE_SUPPORT_STEP_MOTOR
    Ext_InPerStepMotor_Init();
#endif

    ret = Sdk_GetDev_AllInfo();
    if(ret != DEF_COM_SUCCESS)
    {
        PRT_ERR(DEF_TAG,"get dev info failed\n");
        return DEF_COM_FAILED;
    }

    Ext_InSdkSpkPlay_LockInit();
    Ext_InSdkSpkCtrl_Init();
    ret = Ext_SdkMedia_Init();
    if(ret != DEF_COM_SUCCESS)
    {
        PRT_ERR(DEF_TAG,"media init failed !\n");
        return DEF_COM_FAILED;
    }

#if CMAKE_SUPPORT_STEEP_ENGINE
    Ext_InPerSteerEngine_Init();
#endif

    mode = Ext_SdkNetMode_Switch();
    //Path where demo resources locates
    strcpy(s_raw_path, "/tmp");

    tuya_os_adapt_reg_bt_intf();
    tuya_os_bt_intf_init();
    // PRT_INFO(DEF_TAG, "%p\n", tuya_os_adapter_get_intf(INTF_BT));
    // PRT_INFO(DEF_TAG, "%p\n", ((TUYA_OS_BT_INTF *)tuya_os_adapter_get_intf(INTF_BT))->port_init);

    ret = TUYA_IPC_SDK_START(mode, NULL);
    if (ret != 0)
    {
        PRT_ERR(DEF_TAG, "SDK init failed\n");
        return 0;
    }

    IPC_APP_Init_Media_Task();
    IPC_APP_Notify_LED_Sound_Status_CB(IPC_CONNECTING_WIFI);
    Ext_InPerKey_Init();
    Ext_InPerLed_Init();

    if (Ext_InComFile_Access(DEF_FLAG_NO_NETWORK) == DEF_COM_FILE_EXIST)
    {
        Com_s32 ini_ret = Ext_InSdkIniBasic_GetVal(INI_BASIC_VIDEO_NIGHT_MODE_SW);

        UnInSdkIniCfgKeyData udata;

        memset(&udata, 0, sizeof(udata));
        udata.val = ini_ret;
        Ext_InSdkIniIot_SetData(INI_DEV_INT_NIGHT_MODE, &udata);
    }

    Ext_SdkMotionDetectArea_Init();
    Ext_InSdkReboot_Init();

    /* whether SDK is connected to MQTT */
    while((s_mqtt_status != 1) && g_ComThread_Running)
    {
        usleep(10 * 1000);
    }

    if (g_ComThread_Running)
    {
#if CMAKE_SUPPORT_SD_RECORD
        InSdk_SdCardCheck_Init();
#endif

        TUYA_APP_Enable_Motion_Detect();
    }

    while(g_ComThread_Running)
    {
        Ext_SdkWatching_Handle();
        sleep(1);
    }

    while(g_ComThread_Num != 0)
    {
        PRT_WARN(DEF_TAG,"wait [%d] thread exit-----\n",g_ComThread_Num);
        usleep(100 * 1000);
    }

    ret = Ext_SdkMedia_Exit();
    if(ret != DEF_COM_SUCCESS)
    {
        PRT_ERR(DEF_TAG,"media exit failed !\n");
    }

    Ext_InSdkIniCfg_Exit();

#if CMAKE_SUPPORT_STEP_MOTOR
    Ext_InPerStepMotor_Destroy();
#endif

    Ext_InSdkSpkPlay_LockDestroy();

    return 0;
}

